home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PCMania 30
/
PCMania CD30.iso
/
pcmania
/
graf30
/
tacs
/
readimg.c
< prev
next >
Wrap
C/C++ Source or Header
|
1988-04-27
|
20KB
|
876 lines
#include <tiff.h>
#define LINE_SIZE 320
#define BUFFER_SIZE 512
#define NULL 0
#define BITS_PER_BYTE 8
#define ONE_D_MODIFIED_HUFFMAN 2
extern void bigfree();
extern void debug();
extern int sprintf();
extern SHORT read_header();
extern SHORT read_tag();
extern SHORT read_dirent();
extern SHORT decompress_block();
extern SHORT decompress_error;
extern BOOL access_ifd();
extern LONGPTR bigalloc();
extern LONGPTR decblk; /* decompression block */
extern LONGPTR decblk2;
extern SHORT l_compression;
extern LONG lseek();
extern LONG bigRead();
/*
* Declaring a global variable to be "static" causes it to be considered
* global only within this source file. Hence, these "statics" will be
* invisible to any other routines. This avoids unnecessary name clashes
* and keeps these routines and variables out of the load map.
*/
/* static routines */
static LONG get_buffer();
static BOOL readimg_init();
static BOOL read_strip_tables();
static BOOL read_dirct_valu();
/* static global variables */
static SHORT current_handle = (SHORT)(-1);
SHORT readimg_handle = (SHORT)(-1);
static SHORT image_width;
static SHORT compression_type = 0;
static SHORT residual = 0;
static BOOL decompress = FALSE;
static BOOL initialize_read = FALSE;
static BOOL one_at_a_time = FALSE;
static char *dc_ptr = NULL;
static char temp_line_buff[LINE_SIZE];
static char decomp_buffer[BUFFER_SIZE];
static LONG rows_per_strip;
static LONG bytes_per_line;
static LONG start_strip;
static LONG num_strips;
static LONG prev_start_strip = -1L;
static LONG prev_num_strips = -1L;
static LONG strip_index;
static LONG current_line;
static LONG current_byte;
static LONG decomp_bytes_left = 0L;
static LONG num_sb_count;
static LONG off_sb_count;
static LONG num_str_off;
static LONG off_str_off;
static LONG max_strip_size;
static LONG file_position = -1L;
static LONG next_line_to_read = -1L;
static LONG save_file_position = -1L;
static LONG number_of_bytes;
static SHORT samp_per_pix;
static SHORT bits_per_samp;
/*
* These globals are accessible by any routine.
*/
extern LONG far *so_table;
extern LONG far *sbc_table;
LONG _TIFF_image_bytes_read;
LONG _TIFF_image_lines_read;
#ifdef DEBUG
BOOL _TIFF_debug_flag = TRUE;
#else
BOOL _TIFF_debug_flag = FALSE;
#endif /* DEBUG */
LONG bytes_processed = 0;
#ifdef NOWINDOWS
/*
* The flag for one-byte-at-a-time versus buffered mode is a static, so
* that no routine that is linked in can access it. It is set or cleared
* by means of this SetBufferedMode() routine. When debugging, compile
* with the NOWINDOWS flag defined if you want to be able to use this
* routine to alter this mode. Without NOWINDOWS, this routine never
* gets compiled, and so there'd be no way to alter the buffering mode
* from the default value (default == buffered) short of using a debugger
* or patching the code.
*/
void
SetBufferedMode(buffered)
BOOL buffered;
{
if(buffered)
{
one_at_a_time = FALSE;
}
else
{
one_at_a_time = TRUE;
}
}
#endif /* NOWINDOWS */
/* return position of top of IFD list (or zero if error) */
LONG
far get_1st_ifd(fhandle)
SHORT fhandle;
{
static TIFF_HEADER curr_header;
if(fhandle != current_handle)
{
current_handle = fhandle;
if(read_header(fhandle, (TIFF_HEADER far *)&curr_header) !=
TIFF_HEADER_SIZE)
{
return(0L);
}
}
return(curr_header.dir_offset);
}
/* clean up image reading environment */
SHORT
close_read(fhandle)
SHORT fhandle;
{
/* reinitialize handles */
if(current_handle == fhandle)
{
current_handle = (SHORT)(-1);
}
if(readimg_handle == fhandle)
{
readimg_handle = (SHORT)(-1);
}
/* free buffers, reinitialize pointers and sizes */
bigfree(sbc_table);
bigfree(so_table);
if(l_compression == ONE_D_MODIFIED_HUFFMAN) {
bigfree(decblk);
bigfree(decblk2);
}
sbc_table = 0L;
so_table = 0L;
file_position = -1L;
return(1);
}
/* routine to read an image */
LONG
oread_image(fhandle, fdtype, plane, startpos, numlines, buffer, max_length)
SHORT fhandle;
SHORT fdtype;
SHORT plane;
LONG startpos;
LONG numlines;
LONGPTR buffer;
LONG max_length;
{
LONG ifd_offset = get_1st_ifd(fhandle);
LONG bytes_to_be_read;
LONG end_strip;
LONG start_offset;
LONG end_offset;
LONG current_pos;
LONG denominator;
LONG line_offset;
LONG line;
LONG n;
LONG decomp_seek;
_TIFF_image_bytes_read = 0L;
_TIFF_image_lines_read = 0L;
if(!ifd_offset)
{
file_position = -1L;
readimg_handle = -1;
return(0L);
}
/*
* First, get the necessary information from the appropriate tags,
* but only do it if the file handle has changed.
*/
if(readimg_handle != fhandle)
{
if(readimg_init(fhandle, fdtype))
{
file_position = -1L;
readimg_handle = -1;
return(0L);
}
}
/* decide where to start and how many strips to read */
if(rows_per_strip)
{
start_strip = startpos / rows_per_strip;
end_strip = ((numlines - 1) + startpos) /
rows_per_strip;
}
else
{
start_strip = 0L;
end_strip = 0L;
}
/* make sure final strip is contained in file */
if(end_strip >= num_str_off)
{
end_strip = num_str_off - 1;
}
if(end_strip >= num_sb_count)
{
end_strip = num_sb_count - 1;
}
/* don't read if adjusted end strip is below start strip */
if(end_strip < start_strip)
{
readimg_handle = -1;
file_position = -1L;
return(0L);
}
num_strips = (end_strip - start_strip) + 1;
/* re-read the strip tables if necessary */
if(start_strip != prev_start_strip ||
num_strips != prev_num_strips ||
prev_start_strip == -1L ||
prev_num_strips == -1L ||
!sbc_table ||
!so_table)
{
/* new addition to handle rows per strip = image length */
/* vj 1/12/87 */
if(num_str_off == 1)
{
if(read_dirct_valu(fhandle))
{
file_position = -1L;
readimg_handle = -1;
return(0L);
}
}
/* -- -- */
else
{
if(read_strip_tables(fhandle))
{
file_position = -1L;
readimg_handle = -1;
return(0L);
}
}
}
/* get number of bytes per line and total bytes needed */
bytes_per_line = ((LONG)samp_per_pix * (LONG)bits_per_samp * (LONG)image_width) + BITS_PER_BYTE-1;
/* wrong, wrong wrong...... bytes_per_line /= denominator;
bytes per line will only be bytes per line only if you divide
the image_width by 8. Not 8 * number of bits per pixel */
bytes_per_line /= BITS_PER_BYTE; /* bits per byte better be 8 */
bytes_to_be_read = bytes_per_line * numlines;
#ifdef DEBUG
printf("bytes= %d\n",bytes_per_line);
printf("read = %d\n",bytes_to_be_read);
#endif
/* make sure we haven't exceeded maximum buffer size */
if(bytes_to_be_read > max_length)
{
readimg_handle = -1;
bigfree(sbc_table);
bigfree(so_table);
so_table = 0L;
sbc_table = 0L;
file_position = -1L;
return(0L);
}
/* point to beginning of first line */
if(rows_per_strip)
{
line_offset = startpos - start_strip * rows_per_strip;
}
else
{
line_offset = startpos;
}
strip_index = start_strip;
if(next_line_to_read != -1L && next_line_to_read == startpos)
{
decomp_seek = save_file_position;
}
else
{
decomp_seek = -1L;
}
save_file_position = -1L;
next_line_to_read = -1L;
/* read the image data now */
if(decompress)
{
residual = 0;
initialize_read = TRUE;
current_byte = 0L;
/*
* If our start line doesn't begin at the top of the strip
* we have to decompress through the strip line by line,
* ignoring each line until we're positioned at this start
* line.
*/
if(line_offset > 0)
{
debug(" positioning ...\n");
if(decomp_seek < 0L)
{
/* read and ignore the lines */
n = line_offset;
while(n-- > 0)
{
decompress_block(
(LONGPTR)temp_line_buff,
image_width, 1);
if(bytes_processed !=
bytes_per_line)
{
break;
}
}
/* if there was some error, get out */
if(n > 0)
{
readimg_handle = -1;
bigfree(sbc_table);
bigfree(so_table);
so_table = 0L;
sbc_table = 0L;
file_position = -1L;
return(0L);
}
file_position = lseek(readimg_handle, 0L, 1);
}
else
{
file_position = lseek(readimg_handle,
decomp_seek, 0);
if(file_position != decomp_seek)
{
readimg_handle = -1;
bigfree(sbc_table);
bigfree(so_table);
so_table = 0L;
sbc_table = 0L;
file_position = -1L;
return(0L);
}
initialize_read = FALSE;
decomp_bytes_left = 0L;
current_byte = file_position - so_table[0];
}
debug(" after positioning, offset %ld\n", file_position);
}
/*
* If we're here, we are now positioned at the
* correct start position in the image file.
* Just read lines until we're done or until
* there's an error.
*/
n = numlines;
while(n-- > 0 && bytes_to_be_read > 0)
{
/*
* We can only read an integral number of lines
* when decompressing. Hence, we exit if the
* next line read will push us past the total
* number of bytes requested.
*/
if(bytes_to_be_read < bytes_per_line)
{
break;
}
/* decompress into the caller's buffer */
number_of_bytes = 0L;
decompress_block(buffer, image_width, 1);
debug(" read: %ld bytes decompressed into %ld bytes, offset %ld\n",
number_of_bytes, bytes_processed, file_position);
buffer += bytes_processed;
_TIFF_image_bytes_read += bytes_processed;
bytes_to_be_read -= bytes_processed;
if(bytes_processed != bytes_per_line)
{
break;
}
}
}
else /* read uncompressed data */
{
current_byte = line_offset * bytes_per_line;
/* read data directly into caller's data buffer */
while(bytes_to_be_read > 0)
{
/*
* Try to get all remaining data into caller's
* data buffer.
*/
LONG len = get_buffer(buffer, bytes_to_be_read);
/* if no data was retrieved, we're finished */
if(len <= 0)
{
break;
}
/*
* Adjust pointers/totals by actual number of
* bytes read.
*/
buffer += len;
_TIFF_image_bytes_read += len;
bytes_to_be_read -= len;
}
}
_TIFF_image_lines_read = _TIFF_image_bytes_read;
_TIFF_image_lines_read /= bytes_per_line;
save_file_position = file_position;
next_line_to_read = startpos + _TIFF_image_lines_read;
return(_TIFF_image_lines_read);
}
/* read appropriate tags and such */
static BOOL
readimg_init(fhandle, fdtype)
SHORT fhandle;
SHORT fdtype;
{
TIFF_DIR_ENTRY dirent;
readimg_handle = fhandle;
bigfree(so_table);
bigfree(sbc_table);
start_strip = -1L;
prev_start_strip = -1L;
num_strips = 0L;
prev_num_strips = -1L;
so_table = 0L;
sbc_table = 0L;
decomp_bytes_left = 0L;
dc_ptr = NULL;
num_sb_count = 0L;
off_sb_count = 0L;
num_str_off = 0L;
off_str_off = 0L;
max_strip_size = 0L;
compression_type = 0;
decompress = FALSE;
next_line_to_read = -1L;
save_file_position = -1L;
if(!read_tag(fhandle, fdtype, IMAGE_WIDTH_TAG,
(LONGPTR)&image_width, (SHORT)SHORT_SIZE))
{
return(TRUE);
}
/* bits per sample */
if(!read_tag(fhandle, fdtype, BITS_PER_SAMPLE_TAG,
(LONGPTR)&bits_per_samp, (SHORT)SHORT_SIZE))
{
bits_per_samp = 1;
}
/* samples_per_pixel */
if(!read_tag(fhandle, fdtype, SAMPLES_PER_PIXEL_TAG,
(LONGPTR)&samp_per_pix, (SHORT)SHORT_SIZE))
{
samp_per_pix = 1;
}
/* rows per strip */
if(!read_tag(fhandle, fdtype, ROWS_PER_STRIP_TAG,
(LONGPTR)&rows_per_strip, (SHORT)LONG_SIZE))
{
rows_per_strip = 0L;
}
/* compression */
if(!read_tag(fhandle, fdtype, COMPRESSION_TAG,
(LONGPTR)&compression_type, (SHORT)SHORT_SIZE))
{
decompress = FALSE;
}
else
{
/*
* Currently (9/7/86), the only compression this
* routine can handle is the 1-Dimensional Modified
* Huffman run length encoding technique.
*/
switch(compression_type)
{
case ONE_D_MOD_HUFFMAN:
decompress = TRUE;
break;
default:
decompress = FALSE;
compression_type = 0;
}
}
/* strip offsets */
if(!read_dirent(fhandle, fdtype, STRIP_OFFSETS_TAG,
(TIFF_DIR_ENTRY far *)&dirent))
{
return(TRUE);
}
num_str_off = dirent.length;
off_str_off = dirent.value_offset;
/* strip byte counts */
if(!read_dirent(fhandle, fdtype, STRIP_BYTE_COUNTS_TAG,
(TIFF_DIR_ENTRY far *)&dirent))
{
return(TRUE);
}
num_sb_count = dirent.length;
off_sb_count = dirent.value_offset;
debug(" # of strip offsets = %lu, 1st strip offset at %lu\n",
num_str_off, off_str_off);
debug(" # of strip byte counts = %lu, 1st strip byte count at %lu\n",
num_sb_count, off_sb_count);
return(FALSE);
}
/* read the strip offsets and strip bytes counts tables */
static BOOL
read_strip_tables(fhandle)
SHORT fhandle;
{
LONG n;
LONG seek_pos;
LONG read_len;
prev_start_strip = start_strip;
prev_num_strips = num_strips;
bigfree(so_table);
bigfree(sbc_table);
so_table = 0L;
sbc_table = 0L;
/* allocate space for strip offsets table */
so_table = (LONG far *)bigalloc(num_strips * (LONG)LONG_SIZE);
if(!so_table)
{
readimg_handle = -1;
return(TRUE);
}
/* allocate space for strip byte counts table */
sbc_table = (LONG far *)bigalloc(num_strips *
(LONG)LONG_SIZE);
if(!sbc_table)
{
readimg_handle = -1;
bigfree(so_table);
so_table = 0L;
return(TRUE);
}
/* read appropriate portion of strip offsets table */
seek_pos = off_str_off + start_strip * (LONG)LONG_SIZE;
if(lseek(fhandle, seek_pos, 0) != seek_pos)
{
readimg_handle = -1;
file_position = -1L;
bigfree(sbc_table);
bigfree(so_table);
so_table = 0L;
sbc_table = 0L;
return(TRUE);
}
read_len = num_strips * (LONG)LONG_SIZE;
if(bigRead(fhandle, so_table, read_len) != read_len)
{
readimg_handle = -1;
file_position = -1L;
bigfree(sbc_table);
bigfree(so_table);
so_table = 0L;
sbc_table = 0L;
return(TRUE);
}
/* read appropriate portion of strip byte counts table */
seek_pos = off_sb_count + start_strip * (LONG)LONG_SIZE;
if(lseek(fhandle, seek_pos, 0) != seek_pos)
{
readimg_handle = -1;
file_position = -1L;
bigfree(sbc_table);
bigfree(so_table);
so_table = 0L;
sbc_table = 0L;
return(TRUE);
}
read_len = num_strips * (LONG)LONG_SIZE;
if(bigRead(fhandle, sbc_table, read_len) != read_len)
{
readimg_handle = -1;
file_position = -1L;
bigfree(sbc_table);
bigfree(so_table);
so_table = 0L;
sbc_table = 0L;
return(TRUE);
}
/* go through table of strip byte counts and get maximum */
max_strip_size = 0L;
for(n = 0; n < num_strips; ++n)
{
debug(" strip %4ld: offset %lu, byte count %lu\n", n, so_table[n],
sbc_table[n]);
if(max_strip_size < sbc_table[n])
{
max_strip_size = sbc_table[n];
}
}
return(FALSE);
}
/* get a buffer from the file */
static LONG
get_buffer(data_buffer, size)
LONGPTR data_buffer;
LONG size;
{
LONG table_offset = strip_index - start_strip;
LONG bytes_per_strip = sbc_table[table_offset];
LONG seek_pos;
LONG read_len;
LONG len;
/* see if we need to go to the next strip */
if(current_byte >= bytes_per_strip)
{
/* we're done if strip table is exhausted */
if(++table_offset >= num_strips)
{
return(-1L);
}
bytes_per_strip = sbc_table[table_offset];
/* we're done if it's an empty strip */
if(bytes_per_strip < 1)
{
return(-1L);
}
strip_index = start_strip + table_offset;
current_byte = 0L;
residual = 0;
}
/*
* Seek to the appropriate position. Do this each time in case
* the caller has seeked elsewhere in the interim.
*/
seek_pos = so_table[table_offset] + current_byte;
if((file_position = lseek(readimg_handle, seek_pos, 0)) != seek_pos)
{
file_position = -1L;
return(-1L);
}
/* figure out how much to read and then do it */
read_len = size;
if(read_len + current_byte > bytes_per_strip)
{
read_len = bytes_per_strip - current_byte;
}
if(read_len <= 0)
{
return(-1L);
}
len = bigRead(readimg_handle, data_buffer, read_len);
if(len >= 0)
{
current_byte += len;
}
return(len);
}
/*
* This module is to read the stripoffset and stripbytecount values
* when rows per strip is equal to the image length, 1/12/87
*/
static BOOL
read_dirct_valu(fhandle)
SHORT fhandle;
{
LONG n;
prev_start_strip = start_strip;
prev_num_strips = num_strips;
bigfree(so_table);
bigfree(sbc_table);
so_table = 0L;
sbc_table = 0L;
/* allocate space for strip offsets table */
so_table = (LONG far *)bigalloc(num_strips * (LONG)LONG_SIZE);
if(!so_table)
{
readimg_handle = -1;
return(TRUE);
}
/* allocate space for strip byte counts table */
sbc_table = (LONG far *)bigalloc(num_strips *
(LONG)LONG_SIZE);
if(!sbc_table)
{
readimg_handle = -1;
bigfree(so_table);
so_table = 0L;
return(TRUE);
}
*so_table = off_str_off;
*sbc_table = off_sb_count;
max_strip_size = 0L;
for(n = 0; n < num_strips; ++n)
{
debug(" strip %4ld: offset %lu, byte count %lu\n", n, so_table[n],
sbc_table[n]);
if(max_strip_size < sbc_table[n])
{
max_strip_size = sbc_table[n];
}
}
return(FALSE);
}
/*
* General get-byte routine. It's needed for decompression, so I
* might as well use it for uncompressed data as well.
*/
SHORT
GetDecompByte()
{
SHORT ch;
LONG table_offset = strip_index - start_strip;
LONG bytes_per_strip = sbc_table[table_offset];
LONG seek_pos;
#ifdef NOWINDOWS
if(one_at_a_time)
{
if(initialize_read)
{
current_byte = bytes_per_strip;
--table_offset;
initialize_read = FALSE;
}
/* see if we need to go to the next strip */
if(current_byte >= bytes_per_strip)
{
/* we're done if strip table is exhausted */
if(++table_offset >= num_strips)
{
return((SHORT)0xffff);
}
bytes_per_strip = sbc_table[table_offset];
/* we're done if it's an empty strip */
if(bytes_per_strip < 1L)
{
return((SHORT)0xffff);
}
strip_index = start_strip + table_offset;
current_byte = 0L;
residual = 0;
seek_pos = so_table[table_offset];
if((file_position = lseek(readimg_handle, seek_pos,
0)) != seek_pos)
{
file_position = -1L;
return((SHORT)0xffff);
}
}
if(bigRead(readimg_handle, (LONGPTR)&ch, 1L) < 1L)
{
return((SHORT)0xffff);
}
++current_byte;
++number_of_bytes;
file_position = lseek(readimg_handle, 0L, 1);
return(ch & 0xff);
}
else
{
#endif /* NOWINDOWS */
/* read next buffer if necessary */
if(decomp_bytes_left <= 0 || !dc_ptr)
{
decomp_bytes_left =
get_buffer((LONGPTR)decomp_buffer,
(LONG)BUFFER_SIZE);
/* if error or eof, return 0xffff */
if(decomp_bytes_left <= 0)
{
return((SHORT)0xffff);
}
dc_ptr = decomp_buffer;
}
/* return next character */
--decomp_bytes_left;
++file_position;
++number_of_bytes;
ch = (SHORT)(*dc_ptr++);
return(ch & 0xff);
#ifdef NOWINDOWS
}
#endif /* NOWINDOWS */
}